<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    /*
    *
    * 模板方式模式：在父类中定义一组操作算法骨架，
    * 而将一些实现步骤推迟到子类中，使得子类可以不改变父类的算法逻辑结构的同时，
    * 可以出现定义算法中某些实现类
    *
    * 模板方法的核心在于对方法的重用，他将核心方法封装在基类中，让子类继承基类的方法，
    * 实现基类方法的共享，达到方法共用。
    *
     */
//    模板类 基础提示框，data渲染数据
    let Alert = function(data){
    //  没有数据就返回，防止后面程序执行
      if(!data)
        return
    //  设置内容
      this.content = data.content;
    //  创建提示框面板
      this.panel = document.createElement('div');
    //  创建提示内容组件
      this.contentNode = document.createElement('p')
    //  创建确定按钮组件
      this.confirmBtn = document.createElement('span')
    //  创建关闭按钮组件
      this.closeBtn = document.createElement('b')
      //为提示框面板添加类
      this.panel.className = 'alert';
      //为关闭按钮组件添加类
      this.closeBtn.className = 'a-close';
      //为确定按钮组件添加类
      this.confirmBtn.className = 'a-confirm';
      //为确定按钮组件添加文案
      this.confirmBtn.innerHTML = data.confirm || '确认';
      //为提示内容添加文本
      this.contentNode.innerHTML = this.content;
      //点击确定按钮执行方法 如果data中有success方法则为success方法，否则为空函数
      this.success = data.success || function (){};
      //点击关闭按钮执行方法
      this.fail = data.fail || function (){};
    }
//    模板类的原型方法
    Alert.prototype = {
    //  创建方法
      init:function (){
      //  生成提示框
        this.panel.appendChild(this.closeBtn);
        this.panel.appendChild(this.contentNode);
        this.panel.appendChild(this.confirmBtn);
      //  插入页面中
        document.body.appendChild(this.panel);
      //  绑定事件
        this.bindEvent();
      //  显示提示框
        this.show();
      },
      bindEvent: function (){
        let me = this;
      //  关闭按钮点击事件
        this.closeBtn.onclick = function (){
        //  执行关闭取消方法
          me.fail();
        //  隐藏弹层
          me.hide();
        }
        this.confirmBtn.onclick = function () {
        //  执行关闭确认方法
          me.success();
        //  隐藏弹层
          me.hide();
        }
      },
    //  隐藏弹层方法
      hide : function (){
        this.panel.style.display = 'none';
      },
    //  显示弹层方法
      show : function (){
        this.panel.style.display = 'block';
      }
    }

    /*
    *有了模板类，在拓展其他类型的弹层就非常容易了
     */
//    右侧按钮提示框
    let RightAlert = function (data){
    //  继承基本提示框构造函数
      Alert.call(this,data);
    //  为确认按钮添加right类设置位置居右
      this.confirmBtn.className = this.confirmBtn.className + 'right';
    }
    //继承父类的方法
    RightAlert.prototype = new Alert();
//    还可以按照上面的方法创建其他类型的相似子类
//    标题提示框
    let TitleAlert = function (data){
      //  继承基本提示框构造函数
      Alert.call(this,data);
      //设置标题内容
      this.title = data.title;
      //创建标题组件
      this.titleNode = document.createElement('h3');
      //在标题内部写入标题内容
      this.titleNode.innerHTML = this.title;
    }
    //继承父类的方法
    TitleAlert.prototype = new Alert();
    TitleAlert.prototype.init = function (){
    //  插入标题
      this.panel.insertBefore(this.titleNode,this.panel.firstChild);
    //  继承基本提示框init 方法
      Alert.prototype.init.call(this);
    }


//    继承模板的继承类也同样可以作为模板类
//    带有取消按钮的弹出框
    let CancelAlert = function (data){
    //  继承标题提示框的构造函数
      TitleAlert.call(this,data);
    //  取消标题框自己独立的构造函数
      //  取消按钮文案
      this.cancel = data.cancel
      //创建取消按钮
      this.cancelBtn = document.createElement('span')
      //为取消按钮添加类
      this.cancelBtn.className = 'cancel';
      //为确定按钮组件添加文案
      this.cancelBtn.innerHTML = data.cancel || '取消';
    }
//    继承提示框的原型方法,这里继承Alert和TitleAlert都是可以的，
//    因为继承Alert后，init是增强，继承TitleAlert是重写
//    为了出现继承没有重写的问题， 还是继承一个比较干净的Alert比较好
    CancelAlert.prototype = new Alert();
    CancelAlert.prototype.init = function (){
      // 继承标题提示框创建方法
      TitleAlert.prototype.init.call(this);
       //  由于取消按钮要添加在末尾，所以在创建完其他组件后添加
      this.panel.appendChild(this.cancelBtn);
    }
    CancelAlert.prototype.bindEvent = function (){
      let me = this;
      //  标题提示框绑定事件方法继承
      TitleAlert.prototype.bindEvent.call(me);
      this.cancelBtn.onclick = function (){
        //  执行关闭取消方法
        me.fail();
        //  隐藏弹层
        me.hide();
      }
    }
    //这样就很完整了创造了一个模板，可以使用这个模块快速的创造出对象
    //  创建一个提示框
    new CancelAlert({
      title:'提示标题',
      content:'提示内容',
      success: function (){
        console.log('ok')
      },
      fail:function (){
        console.log('cancel')
      }
    }).init()
</script>
</body>
</html>
